<template>
  <div class="jm-bg-color content" ref="zoomBoxRef">
    <div class="left">
      <img src="@/assets/icon/fangda.png" @click="zoomEn()" title="放大" />
      <img src="@/assets/icon/suoxiao.png" @click="zoomOut()" title="缩小" />
      <img src="@/assets/icon/fuwei.png" @click="moveViewToNode()" title="复位" />
      <!-- <img src="@/assets/icon/shangyibu.png" /> -->
      <!-- <img src="@/assets/icon/xiayibu.png" /> -->
      <img src="@/assets/icon/huifumoren.png" @click="nodeReset(searchId?searchId:props.ip)" title="重置" />
    </div>
    <div class="right">
      <!-- <img src="@/assets/icon/sousuo.png" /> -->
      <img src="@/assets/icon/shaixuan.png" @click="filterFlag = !filterFlag" />
      <MyForm class="myForm" v-if="filterFlag" @ShowType="ShowThat" @HideType="HideThat"></MyForm>
    </div>
    <svg ref="chartContainer" width="100%" height="100%"></svg>
    <div class="tooltip" ref="tooltipRef"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, ref, reactive} from 'vue'
import type { AxiosResponse } from 'axios'
import { HttpCodeEnum } from '@packages/share/enums'
// @ts-ignore
import MyForm from '../myform.vue'
// @ts-ignore
import * as d3 from 'd3'
import {
  getManualMeterAPI,
  getManualCountAPI,
  getManualOneAPI,
  getManualMeterTwoAPI
} from '@/api/manual/index'
// 节点图标
import nullBox from '@/assets/icon/null.png'

import { nodeStyles } from './static'
import { getBase64Url, getTarget, createNode } from './utils'

const emit = defineEmits(['getMessage'])
const props = defineProps({
  ip: {
    type: String,
    required: true,
    default: () => { }
  }
})
const searchId = ref()
// 默认Ip
const defaultIP = ref('1.172.179.239')
/* 标志量 */
const NotSureNode = reactive({
  ParentNode: {} as Record<string, any>,
  ThinkNodes: [] as Record<string, any>[]
})
/* 显隐 */
const tooltipRef = ref()
const filterFlag = ref(false)
/* 容器配置 */
const chartContainer = ref(null)
const SvgWidth = ref()
const SvgHeight = ref()
const svg = ref()
const zoom = ref()
const simulation = ref()
const linkGroup = ref()
const nodeGroup = ref()

/* 数据存储 */
const nodes = ref<any[]>([]) //节点
const links = ref<any[]>([]) //关系
const HideNodeType = ref<any[]>([]) //隐藏类
const selectedNode = ref(null) // 当前选中的节点 ID

const ClickNode = ref() //点击节点
// 限制节点数量
const pageSize = 10
const pageNum = 1
// 显示
const ShowThat = (type: string) => {
  // 从 HideNodeType 数组中移除 type 值
  const index = HideNodeType.value.indexOf(type)
  if (index !== -1) {
    HideNodeType.value.splice(index, 1)
    SimulationSet(true)
  }
}
// 隐藏
const HideThat = (type: string) => {
  // 将 type 值添加到 HideNodeType 数组中
  if (!HideNodeType.value.includes(type)) {
    HideNodeType.value.push(type)
    FilterNode()
  }
}
// 过滤
const FilterNode = () => {
  // 筛选出 group_type 不在 HideNodeType 数组中的节点
  const filteredNodes = nodes.value.filter((node) => !HideNodeType.value.includes(node.group_type))
  // 生成新的连接关系数组
  const filteredLinks = links.value.filter((link) => {
    const sourceNode = filteredNodes.find((node) => node.nodeId === link.source.nodeId)
    const targetNode = filteredNodes.find((node) => node.nodeId === link.target.nodeId)
    return sourceNode && targetNode
  })
  // 重新绘制节点和连接
  drawEle(filteredNodes, filteredLinks)
}
// 重置
const nodeReset = (ip:any) => {
  nodes.value = []
  links.value = []
  getInitData(ip)
}
/* 容器配置 */
const GetSvgOptions = () => {
  // 获取容器大小
  const container = d3.select(chartContainer.value).node() // 获取容器的 DOM 元素
  SvgWidth.value = container.getBoundingClientRect().width // 获取容器的宽度
  SvgHeight.value = container.getBoundingClientRect().height // 获取容器的高度
  // 设置容器大小
  svg.value = d3
    .select(chartContainer.value)
    .attr('width', SvgWidth.value)
    .attr('height', SvgHeight.value)
  // 定义缩放行为
  zoom.value = d3
    .zoom()
    .scaleExtent([0.1, 10]) // 设置缩放范围
    .on('zoom', handleZoom)
  svg.value.call(zoom.value) // 应用缩放
  // 封装创建箭头标记的函数
  function createMarker(svg: any, id: any, strokeColor: any, fillColor: any) {
    return svg
      .append('defs')
      .append('marker')
      .attr('id', id)
      .attr('viewBox', '0 -5 10 10') // 视图框
      .attr('refX', 28.2) // 距线终点
      .attr('refY', 0) // 距线左右
      .attr('markerWidth', 10) // 宽度
      .attr('markerHeight', 10) // 高度
      .attr('orient', 'auto') // 自动调整方向
      .append('path')
      .attr('d', 'M0,-5L10,0L0,5') // 箭头路径
      .attr('stroke', strokeColor) // 箭头颜色
      .attr('fill', fillColor) // 箭头填充颜色
  }
  // 定义默认箭头标记
  const defaultMarker = createMarker(svg.value, 'default-arrow', '#ccc', '#ccc')
  // 定义选中状态箭头标记
  const selectMarker = createMarker(svg.value, 'selected-arrow', '#7b7b99', '#7b7b99')
  // 创建链接组和节点组
  linkGroup.value = svg.value.append('g').attr('class', 'links')
  nodeGroup.value = svg.value.append('g').attr('class', 'nodes')
  // 获取初始数据
  getInitData(props.ip)
}
// 初始数据获取
const getInitData = (ip:any) => {
  console.log(ip);
  
  // 不知道为什么props.ip无传入时会为':ip'
  getManualMeterAPI(ip!=':ip'?ip:defaultIP.value).then((res: AxiosResponse) => {
    const { code, data } = res.data
    if (code === HttpCodeEnum.SUCCESS) {
      infoNodeConfig(data)
    }
  })
}
// 前3级节点
const infoNodeConfig = (CoreNode: any) => {
  const { ip, certificate, html_favicon, html_title, port } = CoreNode
  // 核心节点
  nodes.value.push(createNode({
    nodeId: ip,
    name: ip,
    carriedInfo: CoreNode,
    node_type: 'IP',
    icon: getTarget("CHINA", 'icon'),
    group: 'Host',
    leavel: 0,
    XandY: true,
    expand: true,
    childID: [...certificate, ...html_favicon, ...html_title, ...port],
    fx: SvgWidth.value / 2,
    fy: SvgHeight.value / 2
  }))
  // 次级节点
  function addNodesAndLinks(
    Leader_id: string,
    Leader_type: string,
    ChildData: any,
    leavel: number
  ) {
    ChildData = Array.from(new Set(ChildData)) //去重
    const NewID = Leader_id + ':' + ip
    // 组长
    nodes.value.push({
      nodeId: NewID,
      name: Leader_id,
      node_type: Leader_type,
      group_type: getTarget(Leader_type, 'nodetype'),
      group: 'Leader',
      icon: getTarget(Leader_type, 'icon'),
      sourceip: ip,
      leavel: leavel,
      sourcenode: ip,
      expand: false,
      Child: ChildData
    })
    links.value.push({ source: ip, target: NewID })
    // 组员(值)
    ChildData.forEach((item: any) => {
      nodes.value.push({
        nodeId: item,
        name: Leader_type === 'HTML_FAVICON' ? 'icon' : item,
        node_type: getTarget(Leader_type, 'nodetype'),
        group_type: getTarget(Leader_type, 'nodetype'),
        group: 'Members',
        icon: Leader_type === 'HTML_FAVICON' ? getBase64Url(item) : getTarget(Leader_type, 'icon'),
        sourceip: ip,
        leavel: leavel + 1,
        sourcenode: NewID,
        isNew: true, // 添加标志属性
        expand: false
      })
      links.value.push({ source: NewID, target: item })
    })
  }

  if (port?.length > 0) {
    // IP端口节点
    addNodesAndLinks('IP开放的端口', 'PORT', port, 1)
  }
  if (certificate?.length > 0) {
    // IP证书节点
    addNodesAndLinks('绑定IP证书', 'CERTIFICATE', certificate, 1)
  }
  if (html_favicon?.length > 0) {
    // 网页图标节点
    addNodesAndLinks('网页图标', 'HTML_FAVICON', html_favicon, 1)
  }
  if (html_title?.length > 0) {
    // 网页图标节点
    addNodesAndLinks('网页标题', 'HTML_TITLE', html_title, 1)
  }
  emit('getMessage', nodes.value[0])
  // 获取初始坐标
  distanceUpdata()
  // 配置力
  SimulationSet()
  // 视角置中
  moveViewToNode()
}
//初始坐标
function distanceUpdata(initBuild: boolean = true) {
  // 中心点坐标
  const centerX = SvgWidth.value / 2
  const centerY = SvgHeight.value / 2
  const radius = 200 // 距离中心点的位置
  if (initBuild) {
    // 获取所有 leavel 为 1 的节点
    const nodesAtLevel1 = nodes.value.filter((node) => node.leavel === 1)
    const numNodesAtLevel1 = nodesAtLevel1.length
    // 计算每个 leavel 为 1 的节点的坐标
    nodesAtLevel1.forEach((node, index) => {
      const angle = (2 * Math.PI * index) / numNodesAtLevel1
      // node.startangle=angle
      node.x = centerX + radius * Math.cos(angle)
      node.y = centerY + radius * Math.sin(angle)
    })
    // 对leavel为2的节点分组
    const groupedNodes = groupNodes(nodes.value.filter((node) => node.leavel === 2))
    distanceLeavelMore(groupedNodes)
  } else {
    // 对新增节点分组
    const groupedNodes = groupNodes(nodes.value.filter((node) => node.isNew === true))
    distanceLeavelMore(groupedNodes, false)
  }
}
// 3层以上节点坐标设置
function distanceLeavelMore(GroupNodes: any, initFlag: boolean = true) {
  Object.values(GroupNodes).forEach((group) => {
    // 获取当前组的节点数量
    const groupSize = group.Nodes.length
    // 根据 initFlag 确定父节点、祖父节点和来源角度
    const { parent, grandparent, parentAngle } = (() => {
      let Fnode: { sourcenode: any; y: number; x: number }, Gnode, Angle
      if (initFlag) {
        Fnode = group.parent
        Gnode = nodes.value.find((n) => n.nodeId === Fnode.sourcenode)
        Angle = Gnode ? Math.atan2(Fnode.y - Gnode.fy, Fnode.x - Gnode.fx) : 0
      } else {
        Fnode = ClickNode.value
        Gnode = nodes.value.find((n) => n.nodeId === ClickNode.value.sourcenode)
        Angle = Gnode ? Math.atan2(Fnode.y - Gnode.y, Fnode.x - Gnode.x) : 0
      }
      return { parent: Fnode, grandparent: Gnode, parentAngle: Angle }
    })()
    // 根据节点数量分配角度
    group.Nodes.forEach(
      (node: { isNew: any; leavel: number; x: any; y: any; group: any }, index: number) => {
        // 计算新节点的坐标
        // const distanceFromParent = node.group==="Leader"?100:80 // 距离父节点(<连接线：展开;>连接线：拉回)
        const distanceFromParent = 100 // 距离父节点(<连接线：展开;>连接线：拉回)
        // const distanceFromParent = node.leavel * 40 // 距离父节点(<连接线：展开;>连接线：拉回)
        if (groupSize === 1) {
          // 如果当前组的节点数量为 1，直接使用来源角度
          const newAngle = parentAngle
          node.x = parent.x + distanceFromParent * Math.cos(newAngle)
          node.y = parent.y + distanceFromParent * Math.sin(newAngle)
        } else {
          // 如果当前组的节点数量大于 1，将来源角度加减 45 度平均分配
          const angleRange = (Math.PI / 180) * (groupSize * 10) // 差值转换为弧度
          const startAngle = parentAngle - angleRange
          const endAngle = parentAngle + angleRange
          const midAngle = (startAngle + endAngle) / 2 // 角度范围的中点
          // 从中间角度向两边均匀扩散
          const angleStep = angleRange / (groupSize / 2) // 每个节点的角度步长
          // 计算当前节点的角度偏移
          const offset = (index - (groupSize - 1) / 2) * angleStep
          const newAngle = midAngle + offset
          // 计算新节点的坐标
          node.x = parent.x + distanceFromParent * Math.cos(newAngle)
          node.y = parent.y + distanceFromParent * Math.sin(newAngle)
        }
        // 移除 isNew 属性
        delete node.isNew
      }
    )
  })
}
// 节点绘制
function drawNode(selection: any, d: any) {
  const style = nodeStyles[d.group]
  // console.log(d.group);

  // 绘制外圈（如果存在）
  if (style.outerCircle) {
    selection
      .selectAll('circle.Outer-circle')
      .data([d])
      .join(
        (enter: {
          append: (arg0: string) => {
            (): any
            new(): any
            attr: {
              (arg0: string, arg1: string): {
                (): any
                new(): any
                attr: {
                  (
                    arg0: string,
                    arg1: any
                  ): {
                    (): any
                    new(): any
                    attr: {
                      (
                        arg0: string,
                        arg1: any
                      ): {
                        (): any
                        new(): any
                        attr: { (arg0: string, arg1: any): any; new(): any }
                      }
                      new(): any
                    }
                  }
                  new(): any
                }
              }
              new(): any
            }
          }
        }) =>
          enter
            .append('circle')
            .attr('class', 'Outer-circle')
            .attr('r', style.outerCircle.r)
            .attr('fill', style.outerCircle.fill)
            .attr('opacity', style.outerCircle.opacity)
      )
      .merge(selection.selectAll('circle.Outer-circle'))
      .attr('r', style.outerCircle.r)
      .attr('fill', style.outerCircle.fill)
      .attr('opacity', style.outerCircle.opacity)
  }
  // 绘制内圈（如果存在）
  if (style.innerCircle) {
    selection
      .selectAll(`circle.Inner-${d.group.toLowerCase()}-circle`)
      .data([d])
      .join(
        (enter: {
          append: (arg0: string) => {
            (): any
            new(): any
            attr: {
              (
                arg0: string,
                arg1: string
              ): {
                (): any
                new(): any
                attr: {
                  (
                    arg0: string,
                    arg1: any
                  ): {
                    (): any
                    new(): any
                    attr: {
                      (
                        arg0: string,
                        arg1: any
                      ): {
                        (): any
                        new(): any
                        attr: {
                          (
                            arg0: string,
                            arg1: any
                          ): {
                            (): any
                            new(): any
                            attr: { (arg0: string, arg1: any): any; new(): any }
                          }
                          new(): any
                        }
                      }
                      new(): any
                    }
                  }
                  new(): any
                }
              }
              new(): any
            }
          }
        }) =>
          enter
            .append('circle')
            .attr('class', `Inner-${d.group.toLowerCase()}-circle`)
            .attr('r', style.innerCircle.r)
            .attr('stroke', style.innerCircle.stroke || 'none')
            .attr('stroke-width', style.innerCircle.strokeWidth || 0)
            .attr('fill', style.innerCircle.fill)
      )
      .merge(selection.selectAll(`circle.Inner-${d.group.toLowerCase()}-circle`))
      .attr('r', style.innerCircle.r)
      .attr('stroke', style.innerCircle.stroke || 'none')
      .attr('stroke-width', style.innerCircle.strokeWidth || 0)
      .attr('fill', style.innerCircle.fill)
  }
  // 绘制图像（如果存在）
  if (style.image) {
    selection
      .selectAll('image')
      .data([d])
      .join(
        (enter: {
          append: (arg0: string) => {
            (): any
            new(): any
            attr: {
              (
                arg0: string,
                arg1: any
              ): {
                (): any
                new(): any
                attr: {
                  (
                    arg0: string,
                    arg1: any
                  ): {
                    (): any
                    new(): any
                    attr: {
                      (
                        arg0: string,
                        arg1: any
                      ): {
                        (): any
                        new(): any
                        attr: {
                          (
                            arg0: string,
                            arg1: any
                          ): {
                            (): any
                            new(): any
                            attr: { (arg0: string, arg1: any): any; new(): any }
                          }
                          new(): any
                        }
                      }
                      new(): any
                    }
                  }
                  new(): any
                }
              }
              new(): any
            }
          }
        }) =>
          enter
            .append('image')
            .attr('xlink:href', d.icon ? d.icon : nullBox)
            .attr('width', style.image.width)
            .attr('height', style.image.height)
            .attr('x', style.image.x)
            .attr('y', style.image.y)
      )
      .merge(selection.selectAll('image'))
      .attr('xlink:href', d.icon ? d.icon : nullBox)
      .attr('width', style.image.width)
      .attr('height', style.image.height)
      .attr('x', style.image.x)
      .attr('y', style.image.y)
  }
  // 绘制文本（如果存在）
  if (style.text) {
    selection
      .selectAll('text')
      .data([d])
      .join(
        (enter: {
          append: (arg0: string) => {
            (): any
            new(): any
            attr: {
              (
                arg0: string,
                arg1: number
              ): {
                (): any
                new(): any
                attr: {
                  (
                    arg0: string,
                    arg1: any
                  ): {
                    (): any
                    new(): any
                    attr: { (arg0: string, arg1: string): any; new(): any }
                  }
                  new(): any
                }
              }
              new(): any
            }
          }
        }) =>
          enter.append('text').attr('dx', 0).attr('dy', style.text.dy).attr('text-anchor', 'middle')
      )
      .merge(selection.selectAll('text'))
      .text(d.name ? d.name : d.nodeId)
  }
  // 调整渲染顺序(层级)
  ; (function adjustRenderOrder(selection, d) {
    const container = selection.node()
    const elements = [
      container.querySelector('.Outer-circle'),
      container.querySelector(`.Inner-${d.group.toLowerCase()}-circle`),
      container.querySelector('image'),
      container.querySelector('text')
    ]

    // 跳过不存在的层级
    elements.forEach((element) => {
      if (element) {
        container.appendChild(element)
      }
    })
  })(selection, d)
    // 鼠标悬停提示
    ; (function addHoverEvents(selection, tooltipRef) {
      let timeoutId: string | number | NodeJS.Timeout | undefined // 用于存储延时的 ID
      selection
        .on(
          'mouseover',
          (event: { layerX: number; layerY: number }, d: { name: any; nodeId: any }) => {
            // 清除之前的延时（如果存在）
            clearTimeout(timeoutId)
            if (d.name || d.nodeId) {
              // 设置新的延时
              timeoutId = setTimeout(() => {
                const tooltip = tooltipRef.value
                tooltip.textContent = d.name ? d.name : d.nodeId
                tooltip.style.display = 'block'
                tooltip.style.left = `${event.layerX + 10}px`
                tooltip.style.top = `${event.layerY + 10}px`
              }, 500) // 500毫秒延时
            }
          }
        )
        .on('mouseout', () => {
          // 清除延时
          clearTimeout(timeoutId)
          // 隐藏提示框
          tooltipRef.value.style.display = 'none'
        })
    })(selection, tooltipRef)
}
// 主体绘制
function drawEle(Nodes = nodes.value, Links = links.value) {
  // 创建链接元素
  const linkElements = linkGroup.value
    .selectAll('line')
    .data(
      Links,
      (d: { source: { nodeId: any }; target: { nodeId: any } }) =>
        `${d.source.nodeId}-${d.target.nodeId}`
    )
    .join('line')
    .style('stroke', (d: { selected: any }) => (d.selected ? '#7b7b99' : '#ccc'))
    .style('stroke-width', 1)
    .style('stroke-dasharray', (d: { target: any }) =>
      NotSureNode.ThinkNodes.includes(d.target) ? '5,5' : '0'
    )
    .attr('marker-end', (d: { selected: any }) =>
      d.selected ? 'url(#selected-arrow)' : 'url(#default-arrow)'
    )

  // 创建节点元素
  const nodeElements = nodeGroup.value
    .selectAll('g.node')
    .data(Nodes, (d: { nodeId: any }) => d.nodeId)
    .join('g')
    .attr('class', 'node')
    .attr('transform', (d: { x: any; y: any }) => `translate(${d.x},${d.y})`)
    .call(d3.drag().on('start', dragstarted).on('drag', dragged).on('end', dragended))
    .on('click', (event: any, d: any) => {
      NodeClick(d)
    })

  // 更新旧节点的位置
  nodeGroup.value
    .selectAll('g.node')
    .attr('transform', (d: { x: any; y: any }) => `translate(${d.x},${d.y})`)

  // 根据group属性绘制节点
  nodeElements.each(function (d: any) {
    const selection = d3.select(this)
    drawNode(selection, d)
  })

  // 在力引导模拟中添加合并后的 tick 事件监听
  simulation.value.on('tick', tick)

  function dragstarted(event: { active: any }, d: { fx: any; x: any; fy: any; y: any }) {
    if (!event.active) simulation.value.alphaTarget(0.3).restart()
    d.fx = d.x
    d.fy = d.y
  }
  function dragged(event: { x: any; y: any }, d: { fx: any; fy: any }) {
    d.fx = event.x
    d.fy = event.y
  }
  function dragended(event: { active: any }, d: { fx: null; fy: null }) {
    if (!event.active) simulation.value.alphaTarget(0)
    // d.fx = null
    // d.fy = null
  }
  // tick 事件处理函数
  function tick() {
    // 更新链接位置
    linkElements
      .attr('x1', (d: { source: { x: any } }) => d.source.x)
      .attr('y1', (d: { source: { y: any } }) => d.source.y)
      .attr('x2', (d: { target: { x: any } }) => d.target.x)
      .attr('y2', (d: { target: { y: any } }) => d.target.y)
    // 更新节点位置
    nodeElements.attr('transform', (d: { x: any; y: any }) => `translate(${d.x},${d.y})`)
  }
}
// 节点点击事件
const NodeClick = (clicknode: any) => {
  console.log(clicknode);

  ClickNode.value = clicknode
  if (['IP'].includes(clicknode.node_type)) {
    emit('getMessage', clicknode)
    SelectedNode(clicknode) //选择节点
  }
  if (['PORT', 'CERTIFICATE', 'HTML_FAVICON', 'HTML_TITLE'].includes(clicknode.node_type)) {
    if (!clicknode.expand) {
      addSonNodes(clicknode)
    } else {
      emit('getMessage', clicknode)
      SelectedNode(clicknode) //选择节点
    }
  }
  if (['port', 'certificate', 'html_favicon', 'html_title'].includes(clicknode.node_type)) {
    if (NotSureNode.ThinkNodes.length > 0) {
      clearThinkNodes()
    }
    // 是否已展开
    if (!clicknode.expand) {
      getManualCountAPI({ ip: clicknode.sourceip, type: clicknode.node_type, value: clicknode.nodeId }).then(
        (res: AxiosResponse) => {
          const { code, data } = res.data
          if (code === HttpCodeEnum.SUCCESS) {
            clicknode.SonCount = data
            addSonNodes(clicknode)
          }
        }
      )
    }
    if (!clicknode.getinfo) {
      getManualOneAPI({
        ip: clicknode.ip ? clicknode.ip : clicknode.sourceip,
        type: clicknode.node_type,
        value: clicknode.nodeId
      }).then((res: AxiosResponse) => {
        const { code, data } = res.data
        if (code === HttpCodeEnum.SUCCESS) {
          clicknode.carriedInfo = data
          clicknode.getinfo = true
          emit('getMessage', clicknode)
        }
      })
    } else {
      emit('getMessage', clicknode)
      // SelectedNode(clicknode) //选择节点
    }
  }
  if (['domain', 'ipv4', 'ipv6'].includes(clicknode.node_type)) {
    const { sourceip, nodeId, expand, group_type, _value, node_type } = clicknode
    if (!expand) {
      // 获取下级节点
      getManualMeterTwoAPI({
        pageSize,
        pageNum,
        ip: sourceip,
        type: group_type,
        fieldName: node_type === 'ipv4' ? 'ip' : node_type,
        value: _value
      }).then((res: AxiosResponse) => {
        const { code, data } = res.data
        if (code === HttpCodeEnum.SUCCESS) {
          if (data.length > 0) {
            addSonNodes(clicknode, data)
          }
        }
      })
    } else {
      emit('getMessage', clicknode)
      SelectedNode(clicknode) //选择节点
    }
  }
  if (['ip'].includes(clicknode.node_type)) {
    if (!clicknode.getinfo) {
      getManualMeterAPI(clicknode.carriedInfo.id).then((res: AxiosResponse) => {
        const { code, data } = res.data
        if (code === HttpCodeEnum.SUCCESS) {
          clicknode.getinfo = true
          clicknode.carriedInfo = { ...clicknode.carriedInfo, ...data }
          // 更新节点信息
          addSonNodes(clicknode)
        }
      })
    } else {
      //   console.log(11111111111);

      //   // 更新节点信息
      addSonNodes(clicknode)
      //   SelectedNode(clicknode) //选择节点
    }

    // SelectedNode(clicknode) //选择节点
  }
  // SelectedNode(node) //选择节点

  moveViewToNode(clicknode) //视角切换
}
// 添加节点
const addSonNodes = (sourcenode: any, data?: any) => {
  if (['PORT', 'CERTIFICATE', 'HTML_FAVICON', 'HTML_TITLE'].includes(sourcenode.node_type)) {
    const { nodeId, node_type, group_type, sourceip, Child, leavel, originip } = sourcenode
    // 组员(值)
    Child.forEach((item: any) => {
      // 检查 nodes.value 中是否已存在该节点
      const existingNode = nodes.value.find((node: any) => node.nodeId === item)
      // 若不存在，则添加新节点
      if (!existingNode) {
        const newNode = {
          nodeId: item,
          name: node_type === 'HTML_FAVICON' ? 'icon' : item,
          node_type: getTarget(node_type, 'nodetype'),
          group_type: group_type,
          group: 'Members',
          icon: getTarget(node_type, 'icon'),
          sourceip: sourceip,
          originip: originip,
          leavel: leavel + 1,
          sourcenode: nodeId,
          isNew: true, // 是否获取初始位置
          getinfo: false, //是否存储了数据
          expand: false
        }
        nodes.value.push(newNode)
        links.value.push({ source: sourcenode, target: newNode })
      } else {
        sourcenode.fx = sourcenode.x
        sourcenode.fy = sourcenode.y
        existingNode.fx = existingNode.x
        existingNode.fy = existingNode.y
        links.value.push({ source: sourcenode, target: existingNode })
      }
    })
    sourcenode.expand = true
    emit('getMessage', sourcenode)
  }
  if (['port', 'certificate', 'html_favicon', 'html_title'].includes(sourcenode.node_type)) {
    const { domainCount, ipv4Count, ipv6Count } = sourcenode.SonCount //域名,ip4,ip6
    const { nodeId, group_type, sourceip, leavel } = sourcenode
    const newNode = (name: string, childCount: number) => {
      const newNodeId = name + ':' + nodeId
      //  检查是否已存在该节点
      const existingNode = nodes.value.find((node: any) => node.nodeId === newNodeId)
      // 若不存在，则添加新节点
      if (!existingNode) {
        const newNode = {
          nodeId: newNodeId,
          name: name + ':' + childCount,
          node_type: name,
          group_type,
          group: 'Leader',
          sourceip,
          icon: getTarget(name, 'icon'),
          childCount,
          leavel: leavel + 1,
          _value: nodeId,
          sourcenode: nodeId,
          isNew: true, // 添加标志属性
          expand: false
        }
        NotSureNode.ParentNode = sourcenode
        NotSureNode.ThinkNodes.push(newNode)
        // 添加新节点
        nodes.value.push(newNode)
        links.value.push({ source: sourcenode, target: newNode })
      }
    }
    if (ipv4Count > 0) {
      newNode('ipv4', ipv4Count)
    }
    if (ipv6Count > 0) {
      newNode('ipv6', ipv6Count)
    }
    if (domainCount > 0) {
      newNode('domain', domainCount)
    }
  }
  if (['domain', 'ipv4', 'ipv6'].includes(sourcenode.node_type)) {
    const { nodeId, node_type, group_type, sourceip, leavel } = sourcenode
    data.forEach((item: any) => {
      //  检查 nodes.value 中是否已存在该节点
      const existingNode = nodes.value.find((node: any) => node.nodeId === item.ip)
      // 若不存在，则添加新节点
      if (!existingNode) {
        const NewNode = {
          nodeId: item.ip,
          carriedInfo: item,
          node_type: 'ip',
          group_type,
          sourceip,
          icon: getTarget('ip', 'icon'),
          group: 'Members',
          leavel: leavel + 1,
          sourcenode: nodeId,
          getinfo: false,
          isNew: true // 是否给予初始位置
        }
        // 添加新节点
        nodes.value.push(NewNode)
        // 添加新链接
        links.value.push({ source: sourcenode, target: NewNode })
      } else {
        sourcenode.fx = sourcenode.x
        sourcenode.fy = sourcenode.y
        existingNode.fx = existingNode.x
        existingNode.fy = existingNode.y
        links.value.push({ source: sourcenode, target: existingNode })
      }
    })
    sourcenode.expand = true
    sourcenode.Child = FindSon(sourcenode)
    FindDad(sourcenode).Child = sourcenode.Child
    emit('getMessage', sourcenode)
  }
  if (['ip'].includes(sourcenode.node_type)) {
    if (NotSureNode.ThinkNodes.length > 0) { clearThinkNodes() }
    const { ip, port, certificate, html_favicon, html_title } = sourcenode.carriedInfo
    const { nodeId, node_type, group_type, sourceip, leavel } = sourcenode
    // 创建节点和链接的辅助函数
    const addNodesAndLinks = (Leader_id = '', Leader_type = '', ChildData: any) => {
      const NewNodeId = Leader_id + ':' + ip
      //  检查是否已存在该节点
      const existingNode = nodes.value.find((node: any) => node.nodeId === NewNodeId)
      // 若不存在，则添加新节点
      if (!existingNode) {
        const newNode = {
          nodeId: NewNodeId,
          name: Leader_id,
          node_type: Leader_type,
          group_type,
          group: 'Leader',
          icon: getTarget(Leader_type, 'icon'),
          sourceip: ip,
          originip: sourceip,
          leavel: leavel + 1,
          sourcenode: nodeId,
          isNew: true, // 添加标志属性
          Child: ChildData
        }
        // console.log(newNode);
        NotSureNode.ParentNode = sourcenode
        NotSureNode.ThinkNodes.push(newNode)
        // 添加新节点
        nodes.value.push(newNode)
        links.value.push({ source: sourcenode, target: newNode })
      }
    }
    if (port.length > 0) {
      // IP端口节点
      addNodesAndLinks('IP开放的端口', 'PORT', port)
    }
    if (certificate.length > 0) {
      // IP证书节点
      addNodesAndLinks('绑定IP证书', 'CERTIFICATE', certificate)
    }
    if (html_favicon.length > 0) {
      // 网页图标节点
      addNodesAndLinks('网页图标', 'HTML_FAVICON', html_favicon)
    }
    if (html_title.length > 0) {
      // 网页标题节点
      addNodesAndLinks('网页标题', 'HTML_TITLE', html_title)
    }
  }

  SelectedNode(sourcenode) //选择节点
  // 重新启动力导向图的模拟
  // SimulationSet(true)
}
// 查找子节点
const FindSon = (Itnoode: any) => {
  const SonNodes = nodes.value.filter((n) => n.sourcenode === Itnoode.nodeId)
  return SonNodes.map(n => n.nodeId)
}
// 找父节点
const FindDad = (Sonnode: any) => {
  return nodes.value.find((n) => n.nodeId === Sonnode.sourcenode)
}
// 选中节点
const SelectedNode = (node: any) => {
  // 如果点击的是当前选中的节点，取消选中
  if (node === selectedNode.value) {
    selectedNode.value = null
  } else {
    // 否则，更新选中状态
    selectedNode.value = node
  }
  nodes.value.forEach((node) => {
    if (node === selectedNode.value) {
      // 如果当前节点被选中，拼接 "-active"
      node.group = `${node.group}_active`
    } else {
      // 否则，移除 "-active"
      node.group = node.group.replace('_active', '')
    }
  })
  links.value.forEach((link) => {
    const isSourceSelected = selectedNode.value === link.source
    const isTargetSelected = selectedNode.value === link.target
    link.selected = isSourceSelected || isTargetSelected // 设置选中状态
  })
  thinkNode(node)

  // SimulationSet(true)
}
const clearThinkNodes = () => {
  NotSureNode.ThinkNodes.forEach((n) => {
    links.value = links.value.filter((link) => link.target.nodeId !== n.nodeId);
  });
  nodes.value = nodes.value.filter((node) => !NotSureNode.ThinkNodes.some((ns) => ns.nodeId === node.nodeId));
  NotSureNode.ParentNode = {};
  NotSureNode.ThinkNodes = [];
};
const thinkNode = (node: any) => {
  if (NotSureNode.ThinkNodes.length === 0) {
    // 新节点设置位置
    distanceUpdata(false);
    SimulationSet(true);
    return;
  }
  // 子节点(确定展开)
  if (NotSureNode.ThinkNodes.includes(node)) {
    // 从犹豫节点数组中移除该节点
    NotSureNode.ThinkNodes = NotSureNode.ThinkNodes.filter((n) => n.nodeId !== node.nodeId);
    clearThinkNodes();
  }
  // 父节点
  else if (node === NotSureNode.ParentNode) {
    if (!selectedNode.value) {
      clearThinkNodes();
    }
  }
  // 无关节点
  else {
    clearThinkNodes();
  }
  // 新节点设置位置
  distanceUpdata(false);
  SimulationSet(true);
};
// 分组(角度分配计算)
const groupNodes = (Nodes: any) => {
  const groups = {}
  Nodes.forEach((node: { sourcenode: any; leavel: any }) => {
    const parent = nodes.value.find((n: { nodeId: any }) => n.nodeId === node.sourcenode)
    if (parent) {
      const key = `${node.leavel}-${parent.nodeId}` // 使用 leavel 和父节点的 nodeId 作为键
      if (!groups[key]) {
        groups[key] = {
          parent: parent,
          Nodes: []
        }
      }
      groups[key].Nodes.push(node)
    }
  })
  return groups
}
// 节点力配置
const SimulationSet = (RestFlag: boolean = false) => {
  // 初始化
  if (!RestFlag) {
    simulation.value = d3.forceSimulation(nodes.value).force(
      'link',
      d3
        .forceLink(links.value)
        .id((d: any) => d.nodeId)
        .distance(150)
        .strength(0.5)
    )
    // 调用绘制
    drawEle()
  }
  // 重启
  else {
    if (simulation.value) {
      simulation.value.nodes(nodes.value)
      simulation.value.force('link').links(links.value)
      simulation.value.force('link').distance(150).strength(0.5)
      simulation.value.force(
        'collide',
        d3.forceCollide().radius((d: any) => {
          return d.group === 'Host' || d.group === 'Host_active' ? 30 : 20
        })
      )
      simulation.value.alpha(0.3).restart()
      // 重绘
      FilterNode()
    }
  }
}
// 移动视图到目标节点的位置
const moveViewToNode = (node = nodes.value[0]) => {
  const newTransform = d3.zoomIdentity.translate(
    SvgWidth.value / 2 - node.x,
    SvgHeight.value / 2 - node.y
  )
  svg.value
    .transition() // 开始过渡
    .duration(500) // 过渡持续时间，单位为毫秒
    .ease(d3.easeCubic) // 缓动函数
    .call(zoom.value.transform, newTransform)
}
// 视图放大
const zoomEn = () => {
  svg.value.transition().duration(200).call(zoom.value.scaleBy, 2)
}
// 视图缩小
const zoomOut = () => {
  svg.value
    .transition()
    .duration(200)
    .call(zoom.value.scaleBy, 1 / 2)
}
// 缩放处理函数
const handleZoom = (event: any) => {
  // 获取当前缩放的变换信息
  const transform = event.transform
  // 更新链接和节点的位置
  linkGroup.value.attr('transform', transform)
  nodeGroup.value.attr('transform', transform)
}
// 从搜索进入
const show = (ip: string) => {
  searchId.value = ip
  nodeReset(ip)
}
defineExpose({ show })
onMounted(() => {
  // 获取容器配置
  GetSvgOptions()
})
</script>

<style lang="scss" scoped>
.content {
  width: 100%;
  height: 880px;
  position: relative;

  .left {
    float: left;

    img {
      margin-left: 0.725rem;

      &:hover {
        background-color: #ccc;
        /* 鼠标移入时的背景颜色 */
      }
    }
  }

  .right {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 1;

    img {
      margin-right: 0.725rem;

      &:hover {
        background-color: #ccc;
        /* 鼠标移入时的背景颜色 */
      }
    }

    .myForm {
      width: 200px;
      float: right;
    }
  }
}

.tooltip {
  position: absolute;
  background-color: #fff;
  border: 1px solid #ccc;
  padding: 5px 10px;
  border-radius: 5px;
  font-size: 12px;
  pointer-events: none;
  /* 防止鼠标悬停在提示框上时触发其他事件 */
  display: none;
  /* 默认隐藏 */
}
</style>
